package cn.stylefeng.guns.modular.gridsystem.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.stylefeng.guns.core.exception.ServiceException;
import cn.stylefeng.guns.core.factory.PageFactory;
import cn.stylefeng.guns.core.pojo.page.PageResult;
import cn.stylefeng.guns.modular.gridsystem.constants.ConfigSceneConstant;
import cn.stylefeng.guns.modular.gridsystem.constants.GatewayTaskTypeConstant;
import cn.stylefeng.guns.modular.gridsystem.constants.SystemConstant;
import cn.stylefeng.guns.modular.gridsystem.entity.*;
import cn.stylefeng.guns.modular.gridsystem.enums.*;
import cn.stylefeng.guns.modular.gridsystem.mapper.*;
import cn.stylefeng.guns.modular.gridsystem.model.param.BizCollectionSampleManageParam;
import cn.stylefeng.guns.modular.gridsystem.model.param.CheckGatewayResult;
import cn.stylefeng.guns.modular.gridsystem.model.param.CollectionModelParam;
import cn.stylefeng.guns.modular.gridsystem.model.result.BizCollectionSampleManageResult;
import cn.stylefeng.guns.modular.gridsystem.model.result.CollectionResponseResult;
import cn.stylefeng.guns.modular.gridsystem.service.BizCollectionSampleManageService;
import cn.stylefeng.guns.modular.gridsystem.service.CollectionModelService;
import cn.stylefeng.guns.modular.gridsystem.service.GatewayTaskService;
import cn.stylefeng.guns.modular.gridsystem.utils.OptionalBean;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 采集端样本管理 服务实现类
 *
 * @author ssy
 * @date 2022/02/16 10:59
 */
@Service
@Slf4j
public class BizCollectionSampleManageServiceImpl extends ServiceImpl<BizCollectionSampleManageMapper, BizCollectionSampleManage> implements BizCollectionSampleManageService {

    @Resource
    private GatewayTaskService taskService;
    @Resource
    private BizGatewayMapper gatewayMapper;
    @Resource
    private BizGatewayConfigMapper configMapper;
    @Resource
    private GatewayTaskRecordMapper recordMapper;
    @Resource
    private CollectionModelMapper collectionModelMapper;
    @Resource
    private CollectionModelService collectionModelService;

    /**
     * 分页查询采集端样本管理
     *
     * @param bizCollectionSampleManageParam 分页查询入参
     *                                       gatewayId      网关id
     *                                       gatewayCode    网关code
     *                                       gatewayChannel 网关通道
     *                                       gatewayIds     网关ids
     * @return PageResult<BizCollectionSampleManageResult> 网关样本返回
     */
    @Override
    public PageResult<BizCollectionSampleManageResult> page(BizCollectionSampleManageParam bizCollectionSampleManageParam) {
        if (StrUtil.isNotEmpty(bizCollectionSampleManageParam.getGatewayIds())) {
            List<String> gatewayIds = Arrays.asList(bizCollectionSampleManageParam.getGatewayIds().split(SystemConstant.SYMBOL_COMMA));
            bizCollectionSampleManageParam.setGatewayIdList(gatewayIds);
        }
        // 查询分页结果
        return new PageResult<>(baseMapper.page(PageFactory.defaultPage(), bizCollectionSampleManageParam));
    }

    /**
     * 分页查询采集端网关通道样本
     *
     * @param param 分页查询入参
     *              gatewayId      网关id
     *              gatewayChannel 网关通道
     * @return PageResult<BizCollectionSampleManageResult> 网关样本返回
     */
    @Override
    public PageResult<BizCollectionSampleManageResult> pageList(BizCollectionSampleManageParam param) {
        return new PageResult<>(baseMapper.pageList(PageFactory.defaultPage(), param));
    }


    /**
     * 新增采集端样本
     *
     * @param bizCollectionSampleManageParam 新增采集端样本入参
     *                                       gatewayId          网关id
     *                                       gatewayCode        网关编号
     *                                       gatewayChannel     网关通道
     *                                       expectAccessToken  期望ID编号
     *                                       expectGroupId      期望分组号
     *                                       fileId             文件
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(BizCollectionSampleManageParam bizCollectionSampleManageParam) {
        // 将dto转为实体
        BizCollectionSampleManage bizCollectionSampleManage = new BizCollectionSampleManage();
        BeanUtil.copyProperties(bizCollectionSampleManageParam, bizCollectionSampleManage);
        save(bizCollectionSampleManage);
    }

    /**
     * 根据id删除采集端样本 并下发删除模型任务
     *
     * @param param 删除入参
     *              id      主键id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(BizCollectionSampleManageParam param) {
        BizCollectionSampleManageResult sampleManage = detail(param);
        Map<String, Object> map = new HashMap<>();
        map.put(SystemConstant.GATEWAY_CODE, sampleManage.getGatewayCode());
        map.put(SystemConstant.GATEWAY_CHANNEL, sampleManage.getGatewayChannel());
        map.put(SystemConstant.EXPECT_ACCESS_TOKEN, sampleManage.getExpectAccessToken());
        map.put(SystemConstant.EXPECT_GROUP_ID, sampleManage.getExpectGroupId());
        // 下发删除模型任务
        taskService.add(GatewayTaskTypeConstant.DELETE_MODEL, sampleManage.getGatewayId(), JSONUtil.toJsonStr(map));
        removeById(param.getId());
    }

    /**
     * 修改采集端样本信息
     *
     * @param bizCollectionSampleManageParam 修改日志信息入参
     *                                       id            主键id
     *                                       code          通道类型编码
     *                                       name          类型名称
     *                                       fileName      图片
     *                                       remark        备注
     *                                       model         型号
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(BizCollectionSampleManageParam bizCollectionSampleManageParam) {
        BizCollectionSampleManage bizCollectionSampleManage = new BizCollectionSampleManage();
        BeanUtil.copyProperties(bizCollectionSampleManageParam, bizCollectionSampleManage);
        updateById(bizCollectionSampleManage);
    }

    /**
     * 查看注册模型详情
     *
     * @param bizCollectionSampleManageParam 查询入参
     *                                       id      主键id
     * @return BizCollectionSampleManageResult
     */
    @Override
    public BizCollectionSampleManageResult detail(BizCollectionSampleManageParam bizCollectionSampleManageParam) {
        return queryBizCollectionSampleManage(bizCollectionSampleManageParam);
    }

    /**
     * 根据id获取采集端样本
     *
     * @param bizCollectionSampleManageParam 查询入参
     *                                       id      主键id
     * @return BizCollectionSampleManageResult
     */
    private BizCollectionSampleManageResult queryBizCollectionSampleManage(BizCollectionSampleManageParam bizCollectionSampleManageParam) {
        //判断入参不能为空
        OptionalBean.ofNullable(bizCollectionSampleManageParam).orElseThrow(() -> new ServiceException(SystemParamExceptionEnum.PARAM_NULL_ERROR));
        OptionalBean.ofStr(bizCollectionSampleManageParam.getId());
        //根据id获取采集端样本管理
        BizCollectionSampleManage bizCollectionSampleManage = getById(bizCollectionSampleManageParam.getId());
        OptionalBean.ofNullable(bizCollectionSampleManage).orElseThrow(() -> new ServiceException(LogExceptionEnum.NOT_EXISTED));
        BizCollectionSampleManageResult sampleManageResult = new BizCollectionSampleManageResult();
        BeanUtil.copyProperties(bizCollectionSampleManage, sampleManageResult);
        return sampleManageResult;
    }


    /**
     * 注册故障模型
     *
     * @param param 注册故障模型入参
     *              gatewayId       网关id
     *              fileIds         文件id
     *              faultName       异常名称
     *              failureLevel    一场等级
     * @return Long
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long registerModel(BizCollectionSampleManageParam param) {
        //根据网关ID 查询网关的算法分组号和注册算法ID
        CheckGatewayResult checkGatewayResult = checkGateway(param);
        String expectGroupId = checkGatewayResult.getGroupIdCfg().getConfigValue() + param.getChannel();
        String expectAccessToken = String.valueOf(checkGatewayResult.getExpectAccessToken());
        log.info("注册网关故障模型：groupId : {},accessToken : {}", expectGroupId, expectAccessToken);
        //根据故障级别获取相应等级
        Integer enumByName = FailureLevelEnum.findEnumByName(param.getFailureLevel());
        Map<String, Object> map = new HashMap<>();
        map.put(SystemConstant.FAULT_NAME, param.getFaultName());
        map.put(SystemConstant.EXPECT_GROUP_ID, expectGroupId);
        map.put(SystemConstant.EXPECT_ACCESS_TOKEN, expectAccessToken);
        map.put(SystemConstant.FILE_IDS, param.getFileIds());
        map.put(SystemConstant.FAILURE_LEVEL, enumByName);
        CollectionModelParam collectionModelParam = new CollectionModelParam();
        collectionModelParam.setFaultName(param.getFaultName());
        collectionModelParam.setFailureLevel(param.getFailureLevel());
        collectionModelParam.setExpectAccessToken(expectAccessToken);
        collectionModelParam.setExpectGroupId(expectGroupId);
        collectionModelParam.setGatewayId(checkGatewayResult.getGateway().getId());
        if (ObjectUtil.isNotEmpty(param.getFileIds())) {
            String[] fileIds = param.getFileIds().split(SystemConstant.SYMBOL_COMMA);
            collectionModelParam.setFileId(Long.parseLong(fileIds[SystemConstant.NUM_0]));
        }
        log.info("添加网关故障模型：{}", collectionModelParam);
        collectionModelService.add(collectionModelParam);
        return taskService.add(GatewayTaskTypeConstant.REGISTER_MODEL, param.getGatewayId(), JSONUtil.toJsonStr(map));

    }

    /**
     * 注册正样本模型
     *
     * @param param 注册正样本模型入参
     *              channel
     *              gatewayId
     *              fileIds
     * @return Long
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long registerNormalModel(BizCollectionSampleManageParam param) {
        //根据网关ID 查询网关的算法分组号和注册算法ID
        CheckGatewayResult checkGatewayResult = checkGateway(param);
        String expectGroupId = checkGatewayResult.getGroupIdCfg().getConfigValue() + param.getChannel();
        Map<String, Object> map = getStringObjectMap(param, checkGatewayResult, expectGroupId);
        return taskService.add(GatewayTaskTypeConstant.REGISTER_MODEL, param.getGatewayId(), JSONUtil.toJsonStr(map));

    }

    /**
     * 根据网关和任务Id查询远程任务响应
     *
     * @param param 查询入参
     *              gatewayId   网关ID
     *              taskId      任务ID
     * @return CollectionResponseResult
     */
    @Override
    public CollectionResponseResult queryTask(BizCollectionSampleManageParam param) {
        CollectionResponseResult res = null;
        LambdaQueryWrapper<GatewayTaskRecord> queryWrapperByCode = new LambdaQueryWrapper<>();
        queryWrapperByCode.eq(GatewayTaskRecord::getGatewayId, param.getGatewayId());
        queryWrapperByCode.eq(GatewayTaskRecord::getTaskId, param.getTaskId());
        queryWrapperByCode.last(SystemConstant.SQL_LIMIT);
        GatewayTaskRecord record = recordMapper.selectOne(queryWrapperByCode);
        if (ObjectUtil.isNotEmpty(record.getResponseResult())) {
            res = JSON.parseObject(record.getResponseResult(), CollectionResponseResult.class);
            if (CollectionFaultEnum.GROUP_ID_OR_ACCESS_TOKEN_ERROR.getCode().equals(res.getCode())) {
                res.setMsg(CollectionFaultEnum.GROUP_ID_OR_ACCESS_TOKEN_ERROR.getMessage());
            }
            if (CollectionFaultEnum.COLLECTION_CAN_NOT_GET_FILE.getCode().equals(res.getCode())) {
                res.setMsg(CollectionFaultEnum.COLLECTION_CAN_NOT_GET_FILE.getMessage());
            }
            if (CollectionFaultEnum.COLLECTION_NO_RESPONSE.getCode().equals(res.getCode())) {
                res.setMsg(CollectionFaultEnum.COLLECTION_NO_RESPONSE.getMessage());
            }
            if (CollectionFaultEnum.COLLECTION_SERVER_ERROR.getCode().equals(res.getCode())) {
                res.setMsg(CollectionFaultEnum.COLLECTION_SERVER_ERROR.getMessage());
            }
        }
        return res;
    }

    /**
     * 根据网关ID 查询网关的算法分组号和注册算法ID
     *
     * @param param 查询网关id
     * @return CheckGatewayResult
     */
    private CheckGatewayResult checkGateway(BizCollectionSampleManageParam param) {
        //入参判断
        OptionalBean.ofNullable(param).orElseThrow(() -> new ServiceException(SystemParamExceptionEnum.PARAM_NULL_ERROR));
        OptionalBean.ofStr(param.getGatewayId());
        //查询网关
        BizGateway gateway = gatewayMapper.selectById(param.getGatewayId());
        log.warn("网关主键为:{}", param.getGatewayId());
        OptionalBean.ofNullable(gateway).orElseThrow(() -> new ServiceException(GatewayExceptionEnum.NOT_EXIST));

        //查询算法分组号
        BizGatewayConfig groupIdCfg = configMapper.selectOne(new LambdaQueryWrapper<BizGatewayConfig>()
                .eq(BizGatewayConfig::getGatewayId, gateway.getId())
                .eq(BizGatewayConfig::getGatewayConfigCode, ConfigSceneConstant.MIC_GROUP_ID).last(SystemConstant.SQL_LIMIT));
        OptionalBean.ofNullable(groupIdCfg).orElseThrow(() -> new ServiceException(GatewayExceptionEnum.NOT_CONFIG_GROUP_ID));

        //查询注册算法ID
        BizGatewayConfig accessTokenCfg = configMapper.selectOne(new LambdaQueryWrapper<BizGatewayConfig>()
                .eq(BizGatewayConfig::getGatewayId, gateway.getId())
                .eq(BizGatewayConfig::getGatewayConfigCode, ConfigSceneConstant.MIC_ACCESS_TOKEN).last(SystemConstant.SQL_LIMIT));
        OptionalBean.ofNullable(accessTokenCfg).orElseThrow(() -> new ServiceException(GatewayExceptionEnum.NOT_CONFIG_ACCESS_TOKEN));

        CollectionModel collectionModel = collectionModelMapper.selectOne(new LambdaQueryWrapper<CollectionModel>()
                .eq(CollectionModel::getGatewayId, gateway.getId())
                .orderByDesc(CollectionModel::getExpectAccessToken).last(SystemConstant.SQL_LIMIT));
        long expectAccessToken = Long.parseLong(groupIdCfg.getConfigValue() + param.getChannel() + SystemConstant.NUM_001);

        if (ObjectUtil.isNotNull(collectionModel)) {
            expectAccessToken = Long.parseLong(collectionModel.getExpectAccessToken()) + SystemConstant.NUM_1;
            log.info("groupId中存在故障模型，期望accessToken为：{}", expectAccessToken);
        }
        return CheckGatewayResult.builder().gateway(gateway).accessTokenCfg(accessTokenCfg).groupIdCfg(groupIdCfg).expectAccessToken(expectAccessToken).build();
    }

    /**
     * @param param              采集端样本
     * @param checkGatewayResult 算法入参
     * @param expectGroupId      算法分组号
     * @return Map<String, Object> 拼接入参
     */
    private static Map<String, Object> getStringObjectMap(BizCollectionSampleManageParam param,
                                                          CheckGatewayResult checkGatewayResult,
                                                          String expectGroupId) {
        String expectAccessToken = checkGatewayResult.getAccessTokenCfg().getConfigValue() + param.getChannel();
        //组装任务参数
        Map<String, Object> map = new HashMap<>();
        map.put(SystemConstant.EXPECT_GROUP_ID, expectGroupId);
        map.put(SystemConstant.EXPECT_ACCESS_TOKEN, expectAccessToken);
        map.put(SystemConstant.FILE_IDS, param.getFileIds());
        map.put(SystemConstant.FAILURE_LEVEL, SystemConstant.ZERO);
        map.put(SystemConstant.FAULT_NAME, SystemConstant.NORMAL);
        return map;
    }


}
